﻿namespace Nomo.CoreModule
{
    /// <summary>
    /// 表示毫秒时间戳。
    /// </summary>
    public readonly struct MillisecondTimeStamp : System.IEquatable<MillisecondTimeStamp>
    {
        private const    long DateTime19700101Ticks = 621355968000000000L;
        private const    long TicksPerMillisecond   = 10000L;
        private const    long MillisecondPerSecond  = 1000L;
        private readonly long _millisecond;

        private MillisecondTimeStamp(long millisecond)
        {
            _millisecond = millisecond;
        }

        /// <summary>
        /// 将时刻转换为毫秒时间戳。
        /// </summary>
        /// <param name="dateTime">时刻。</param>
        /// <returns>毫秒时间戳。</returns>
        public static explicit operator MillisecondTimeStamp(System.DateTime dateTime)
        {
            return new MillisecondTimeStamp((dateTime.ToUniversalTime().Ticks - DateTime19700101Ticks) / TicksPerMillisecond);
        }

        /// <summary>
        /// 将毫秒时间戳转换为时刻。
        /// </summary>
        /// <param name="millisecondTimeStamp">毫秒时间戳。</param>
        /// <returns>时刻。</returns>
        public static explicit operator System.DateTime(MillisecondTimeStamp millisecondTimeStamp)
        {
            return new System.DateTime(millisecondTimeStamp._millisecond * TicksPerMillisecond + DateTime19700101Ticks).ToLocalTime();
        }

        /// <summary>
        /// 将表示毫秒时间戳的毫秒数转换为毫秒时间戳。
        /// </summary>
        /// <param name="millisecond">表示毫秒时间戳的毫秒数。</param>
        /// <returns>毫秒时间戳。</returns>
        public static explicit operator MillisecondTimeStamp(long millisecond)
        {
            return new MillisecondTimeStamp(millisecond);
        }

        /// <summary>
        /// 将毫秒时间戳转换为表示毫秒时间戳的毫秒数。
        /// </summary>
        /// <param name="millisecondTimeStamp">毫秒时间戳。</param>
        /// <returns>表示毫秒时间戳的毫秒数。</returns>
        public static explicit operator long(MillisecondTimeStamp millisecondTimeStamp)
        {
            return millisecondTimeStamp._millisecond;
        }

        /// <summary>
        /// 将 Unix 时间戳转换为毫秒时间戳。
        /// </summary>
        /// <param name="unixTimeStamp">Unix 时间戳。</param>
        /// <returns>毫秒时间戳。</returns>
        public static explicit operator MillisecondTimeStamp(UnixTimeStamp unixTimeStamp)
        {
            return (MillisecondTimeStamp) ((long) unixTimeStamp * MillisecondPerSecond);
        }

        /// <summary>
        /// 将毫秒时间戳转换为 Unix 时间戳。
        /// </summary>
        /// <param name="millisecondTimeStamp">毫秒时间戳。</param>
        /// <returns>Unix 时间戳。</returns>
        public static explicit operator UnixTimeStamp(MillisecondTimeStamp millisecondTimeStamp)
        {
            return (UnixTimeStamp) ((long) millisecondTimeStamp / MillisecondPerSecond);
        }

        /// <inheritdoc />
        public bool Equals(MillisecondTimeStamp other)
        {
            return _millisecond == other._millisecond;
        }

        /// <inheritdoc />
        public override bool Equals(object obj)
        {
            return obj is MillisecondTimeStamp millisecondTimeStamp && Equals(millisecondTimeStamp);
        }

        /// <inheritdoc />
        public override int GetHashCode()
        {
            return _millisecond.GetHashCode();
        }

        /// <inheritdoc />
        public override string ToString()
        {
            return $"{(System.DateTime) this} ({_millisecond})";
        }
    }
}
